using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Web;
using CKS.EBE.Linkbacks;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using System.Diagnostics;
using Microsoft.Web.Administration;

namespace CKS.EBE
{
	public class WebApplicationFeatureReceiver : SPFeatureReceiver
	{
		public override void FeatureActivated(SPFeatureReceiverProperties properties)
		{
			try
			{
				var oApp = (SPWebApplication)properties.Feature.Parent;
				Collection<SPWebConfigModification> modifications = oApp.WebConfigModifications;
				double iisVersion = GetIisVersion();
				ManagedPipelineMode pipelineMode = GetIntegrationMode(iisVersion, oApp.ApplicationPool);
				string iisSpecificLocationForModules;
				string iisSpecificLocationForHandler;
				if (pipelineMode == ManagedPipelineMode.Classic)
				{
					iisSpecificLocationForModules = "configuration/system.web/httpModules";
					iisSpecificLocationForHandler = "configuration/system.web/httpHandlers";
				}
				else
				{
					// in IIS 7 httpmodules need to be added to a different element in the web.config
					iisSpecificLocationForModules = "configuration/system.webServer/modules";
					iisSpecificLocationForHandler = "configuration/system.webServer/handlers";
				}
				modifications.Add(CreateModification("add[@name='CksEbeModule']",
																 iisSpecificLocationForModules,
																 string.Format("<add name='CksEbeModule' type='{0}' />", typeof(BlogHttpModule).AssemblyQualifiedName)));

				modifications.Add(CreateModification("SafeControl[@Namespace='CKS.EBE.WebControls']",
																 "configuration/SharePoint/SafeControls",
																 string.Format("<SafeControl Assembly='{0}' Namespace='CKS.EBE.WebControls' TypeName='*' Safe='True' />", typeof(BlogHttpModule).Assembly.FullName)));

				modifications.Add(CreateModification("add[@expressionPrefix='BlogUrl']",
																 "configuration/system.web/compilation/expressionBuilders",
																 string.Format("<add expressionPrefix='BlogUrl' type='{0}'/>", typeof(ThemeExpressionBuilder).AssemblyQualifiedName)));

				// Added for easy translation (no need to sync resx to App_GlobalResource)
				modifications.Add(CreateModification("add[@expressionPrefix='SPResources']",
																 "configuration/system.web/compilation/expressionBuilders",
																 string.Format("<add expressionPrefix='SPResources' type='{0}'/>", typeof(ResourcesExpressionBuilder).AssemblyQualifiedName)));

				// IIS 7 needs a name attribute in integrated mode. IIS 6 must not have one
				bool needNameAttribute = pipelineMode == ManagedPipelineMode.Integrated;
				modifications.Add(CreateModification("add[@path='*/rss.xml']",
																 iisSpecificLocationForHandler,
																 string.Format("<add {1}verb='*' path='*/rss.xml' type='{0}'/>", typeof(RssHandler).AssemblyQualifiedName, needNameAttribute ? "name='EBERss' " : "")));

				modifications.Add(CreateModification("add[@path='*/pingback.axd']",
																 iisSpecificLocationForHandler,
																 string.Format("<add {1}verb='*' path='*/pingback.axd' type='{0}'/>", typeof(PingbackPinger).AssemblyQualifiedName, needNameAttribute ? "name='EBEPingback' " : "")));

				modifications.Add(CreateModification("add[@path='*/rsdAutoDiscovery.axd']",
																 iisSpecificLocationForHandler,
																 string.Format("<add {1}verb='*' path='*/rsdAutoDiscovery.axd' type='{0}'/>", typeof(RsdHandler).AssemblyQualifiedName, needNameAttribute ? "name='EBERsdAutoDiscovery' " : "")));

				modifications.Add(CreateModification("add[@path='*/wlwautodiscovery.axd']",
																 iisSpecificLocationForHandler,
																 string.Format("<add {1}verb='*' path='*/wlwautodiscovery.axd' type='{0}'/>", typeof(WlwHandler).AssemblyQualifiedName, needNameAttribute ? "name='EBEWlwAutoDiscovery' " : "")));
				oApp.Update();

				SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

				//UpdateSitemap uls = new UpdateSitemap(oApp);
				//uls.AddEntry("Blog Settings", "/_layouts/cks/ebe/settings.aspx", "/_layouts/settings.aspx");
				//uls.SubmitJob();

				// create job which will iterate through all webs and look for ebe enabled blogs.
				// if it contains a post for which we need to perform pingbacks, do it
				var job = new LinkbackJob("Send Trackbacks and Pingbacks", oApp);
				if (!job.JobAlreadyExists())
				{
					job.SubmitJob();
				}
			}
			catch (Exception ex)
			{
				throw new SPException("Exeption activating webapplication feature: " + ex);
			}
		}

		/// <summary>
		/// if the iis is an iis 7, check if the application pool is running in classic mode. iis 6 is always classic mode
		/// </summary>
		/// <param name="iisVersion"></param>
		/// <param name="applicationPool"></param>
		/// <returns></returns>
		private static ManagedPipelineMode GetIntegrationMode(double iisVersion, SPApplicationPool applicationPool)
		{
			if (iisVersion < 7)
			{
				// treat old iis versions as classic mode
				return ManagedPipelineMode.Classic;
			}

			using (var serverManager = new ServerManager())
			{
				Configuration config = serverManager.GetApplicationHostConfiguration();
				ConfigurationSection applicationPoolsSection = config.GetSection("system.applicationHost/applicationPools");
				ConfigurationElementCollection applicationPoolsCollection = applicationPoolsSection.GetCollection();

				foreach (ConfigurationElement element in applicationPoolsCollection)
				{
					if ((string)element["name"] == applicationPool.Name)
					{
						return (ManagedPipelineMode) element["managedPipelineMode"];
					}
				}
			}
			return ManagedPipelineMode.Classic;
		}

		private static SPWebConfigModification CreateModification(string name, string path, string value)
		{
			SPWebConfigModification oModification = new SPWebConfigModification(name, path);
			oModification.Owner = "CksEbeExtensions";
			oModification.Value = value;
			oModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;

			return oModification;
		}

		public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
		{
			try
			{
				var oApp = (SPWebApplication)properties.Feature.Parent;
				var toRemove = new List<SPWebConfigModification>();

				foreach (SPWebConfigModification m in oApp.WebConfigModifications)
				{
					if (m.Owner == "CksEbeExtensions") toRemove.Add(m);
				}

				foreach (SPWebConfigModification m in toRemove)
				{
					oApp.WebConfigModifications.Remove(m);
				}

				oApp.Update();

				SPFarm.Local.Services.GetValue<SPWebService>().ApplyWebConfigModifications();

				// remove jobs
				Guid sitemapJob = Guid.Empty;
				Guid pingbackJob = Guid.Empty;
				foreach (SPJobDefinition jobDefinition in oApp.JobDefinitions)
				{
					if (jobDefinition.Title.StartsWith("Update Layouts Sitemap ("))
					{
						sitemapJob = jobDefinition.Id;
					}
					else if (jobDefinition.Title == "Send Trackbacks and Pingbacks (" + oApp.Name + ")")
					{
						pingbackJob = jobDefinition.Id;
					}
				}
				if (sitemapJob != Guid.Empty)
				{
					oApp.JobDefinitions.Remove(sitemapJob);
				}
				if (pingbackJob != Guid.Empty)
				{
					oApp.JobDefinitions.Remove(pingbackJob);
				}
			}
			catch (Exception ex)
			{
				Trace.WriteLine("Error deactivating CKS:EBE WebApp Feature");
				Trace.WriteLine(ex);
			}
		}

		public override void FeatureInstalled(SPFeatureReceiverProperties properties)
		{

		}

		public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
		{

		}

		/// <summary>
		/// Detect IIS version from server variable
		/// </summary>
		/// <returns></returns>
		private static double GetIisVersion()
		{
			double version = 0.0;
			try
			{
				string serverSoftware = HttpContext.Current.Request.ServerVariables["SERVER_SOFTWARE"];

				if (serverSoftware.StartsWith("Microsoft-IIS/"))
				{
					serverSoftware = serverSoftware.Replace("Microsoft-IIS/", "");
					double.TryParse(serverSoftware, out version);
				}
			}
			catch (Exception ex)
			{
				throw new SPException("Cannot get IIS Version. " + ex.Message);
			}
			return version;
		}
	}
}